<MudDataGrid T="Model"
             @ref="_gridComponentReference"
             Virtualize="true"
             VirtualizeServerData="ServerDataFunc"
             FixedHeader="true"
             Height="350px"
             Groupable>
    <ToolBarContent>
        <MudText Typo="Typo.h6">MudBlazor grid</MudText>
        <MudSpacer />
        <MudTextField T="string?" @bind-Value:get="_searchString" @bind-Value:set="SetSearchString" Placeholder="Search" Adornment="Adornment.Start" Immediate="true"
                      AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0" />
    </ToolBarContent>
    <NoRecordsContent>
        No data
    </NoRecordsContent>
    <Columns>
        <PropertyColumn Property="x => x.Index" Grouping />
        <PropertyColumn Property="x => x.Column2" />
    </Columns>
</MudDataGrid>
<MudExpansionPanels Style="flex:1">
    <MudExpansionPanel Text="Show Events">
        @foreach (var message in _events)
        {
            <MudText Typo="@Typo.body2">@message</MudText>
        }
        @if (_events.Count > 0)
        {
            <div class="d-flex">
                <MudButton Class="mt-3" ButtonType="ButtonType.Button" Variant="Variant.Filled" OnClick="@StateHasChanged">Update</MudButton>
                <MudSpacer />
                <MudButton Class="mt-3" ButtonType="ButtonType.Button" Variant="Variant.Filled" OnClick="@(() => _events.Clear())">Clear</MudButton>
            </div>
        }
    </MudExpansionPanel>
</MudExpansionPanels>

@code {
    public static string __description__ = @"The data grid should reload data correctly when using VirtualizeServerData with external filter. Empty result must show 'No data'.";

    private readonly List<string> _events = [];
    private string? _searchString;
    private MudDataGrid<Model>? _gridComponentReference;

    private readonly IEnumerable<Model> _sourceElements = Enumerable.Range(0, 100)
            .Select(i => new Model(i, $"Value_{i}"))
            .ToArray();
    private IEnumerable<Model> _elements = Enumerable.Empty<Model>();

    protected override void OnInitialized()
    {
        _elements = _sourceElements;
    }

    /// <summary>
    /// Reloads the data from the server, with support for cancellation.
    /// </summary>
    private async Task<GridData<Model>> ServerDataFunc(GridStateVirtualize<Model> state, CancellationToken token)
    {
        try
        {
            // Simulate "loading data"
            await Task.Delay(500, token);

            IEnumerable<Model> data = _elements;

            data = data
                .Skip(state.StartIndex)
                .Take(state.Count)
                .ToList();

            // Return the data
            var result = new GridData<Model>() { TotalItems = _elements.Count(), Items = data.ToArray() };
            _events.Add($"ServerDataFunc index : {state.StartIndex} (TotalItems : {result.TotalItems})");

            return result;
        }
        catch (Exception ex) when (ex is TaskCanceledException)
        {
            _events.Add($"ServerDataFunc index : {state.StartIndex} (Cancelled)");
            return new GridData<Model>
            {
                Items = [],
                TotalItems = 0,
            };
        }
    }

    private Task SetSearchString(string? searchValue)
    {
        _searchString = searchValue;
        if (string.IsNullOrEmpty(searchValue))
        {
            _elements = _sourceElements;
        }
        else
        {
            _elements = _sourceElements.Where(x =>
                    x.Index.ToString() == searchValue
                    || (x.Column2?.Contains(searchValue, StringComparison.OrdinalIgnoreCase) ?? false)
                );
        }
        return _gridComponentReference?.ReloadServerData() ?? Task.CompletedTask;
    }

    public record Model(int Index, string Column2);
}